package com.thx.log;

import java.util.Date;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.thx.common.spring.BeanFactory;
import com.thx.common.util.ThreadLocalContext;
import com.thx.common.web.SessionInfo;
import com.thx.common.web.WebConstant;
import com.thx.common.web.util.IpUtil;
import com.thx.log.model.Log;
import com.thx.log.service.LogManager;

/**
 * 记录日志
 *
 * @author balance
 *
 */
public class LogUtil {

	private static Logger _log = LoggerFactory.getLogger(LogUtil.class);

	public static final String ACTION_ADD = "新增";

	public static final String ACTION_UPDATE = "修改";

	public static final String ACTION_DELETE = "删除";

	public static final String ACTION_SEARCH = "查询";

	public static final String ACTION_LOGIN = "登录";

	public static final String ACTION_LOGOUT = "退出";

	public static final String RESULT_SUCCESS = "成功";

	public static final String RESULT_FAIL = "失败";

	/**
	 * 记录日志
	 *
	 * @param appName
	 *            应用名称
	 * @param module
	 *            功能模块
	 * @param action
	 *            操作
	 * @param result
	 *            操作结果
	 * @param description
	 *            描述
	 * @param allowDel
	 *            是否允许删除
	 * @param isAsyn
	 *            是否异步
	 */
	public static void log(String appName, String module, String action, String result, String description, boolean allowDel, boolean isAsyn) {
		try {
			if (isAsyn) {
				final Log log = getLog(appName, module, action, result, description, allowDel);
				Thread thread = new Thread(new Runnable() {
					public void run() {
						LogManager logManager = (LogManager) BeanFactory.getBean("logManager");
						logManager.save(log);
					}
				});
				thread.start();

			} else {
				Log log = getLog(appName, module, action, result, description, allowDel);
				LogManager logManager = (LogManager) BeanFactory.getBean("logManager");
				logManager.save(log);
			}

		} catch (Exception e) {
			_log.error("记录日志失败！", e);
		}

	}

	/**
	 * 日志默认不允许删除
	 *
	 * @param appName
	 *            应用名称
	 * @param module
	 *            功能模块
	 * @param action
	 *            操作
	 * @param result
	 *            操作结果
	 * @param description
	 *            描述
	 * @param isAsyn
	 *            是否异步
	 */
	public static void log(String appName, String module, String action, String result, String description, boolean isAsyn) {
		log(appName, module, action, result, description, false, isAsyn);
	}

	/**
	 * 同步记录日志，日志默认不允许删除,appName自动获取顺序——>web.xml(display-name)——>webRoot
	 *
	 * @param module
	 *            功能模块
	 * @param action
	 *            操作
	 * @param result
	 *            操作结果
	 * @param description
	 *            描述
	 */
	public static void log(String module, String action, String result, String description) {
		log(null, module, action, result, description, false);
	}

	/**
	 * 获取log实体
	 */
	private static Log getLog(String appName, String module, String action, String result, String description, boolean allowDel) {

		Log log = new Log();

		log.setModule(module);
		log.setAction(action);
		log.setResult(result);
		log.setDescription(description);
		log.setAllowDelete(allowDel ? Log.ALLOW_DEL : Log.NOT_ALLOW_DEL);
		log.setCreateDate(new Date());

		SessionInfo user = (SessionInfo) ThreadLocalContext.get(WebConstant.KEY_USER);

		HttpServletRequest request = getRequest();

		if (user == null && request != null){
			_log.debug("线程未绑定变量："+WebConstant.KEY_USER+"=null");
			HttpSession session = request.getSession();
			user = (SessionInfo) (session.getAttribute(WebConstant.KEY_USER));
			_log.debug("request.session中取得 用户信息：userId="+(user==null?"null":user.getUserId())+",sessionId="+session.getId());
		}

		if (user != null) {
			log.setUserId(user.getUserId());
			log.setUserName(user.getRealName());
			log.setComId(user.getComId());
		}else{
			_log.debug("无用户信息，sessionId="+request.getSession().getId());
			log.setUserId("null");
			log.setUserName("无用户");
			log.setComId("null");
		}

		if (request != null) {

			if (StringUtils.isBlank(appName)) {
				appName = request.getSession().getServletContext().getServletContextName();
			}

			if (StringUtils.isBlank(appName)) {
				String webRoot = request.getContextPath();
				appName = webRoot.substring(webRoot.indexOf("/") + 1);
			}
			log.setAppName(appName);

			String proxyIp = IpUtil.proxyIp(request);
			String realityIp = IpUtil.realityIp(request);

			log.setProxyIp(proxyIp);
			log.setRealityIp(realityIp);

			/*外网查询ip归属地，影响程序响应速度*/
			/*if (StringUtils.isNotBlank(realityIp)) {
				String area = IpUtil.getAddressByIp(realityIp);
				log.setIpArea(area);
			}*/

			String device = request.getHeader("User-Agent");

			if (StringUtils.isBlank(device))
				device = (String) request.getAttribute(WebConstant.DEVICE);

			log.setDevice(device);

			String accessType = (String) request.getAttribute(WebConstant.ACCESS_TYPE);

			if (StringUtils.isBlank(accessType))
				accessType = "未知访问方式";

			log.setAccessType(accessType);

			String requestId = (String) request.getAttribute("requestId");

			if (StringUtils.isBlank(requestId)) {
				requestId = System.currentTimeMillis() + "" + request.hashCode();
				request.setAttribute("requestId", requestId);
			}
			log.setRequestId(requestId);
		}
		return log;
	}

	/**
	 * 获取request对象
	 *
	 * @return
	 */
	private static HttpServletRequest getRequest() {

		HttpServletRequest request = (HttpServletRequest) ThreadLocalContext.get(WebConstant.CURRENT_REQUEST);
		_log.debug("线程绑定的变量：" + WebConstant.CURRENT_REQUEST + "=" + (request == null ? "null" : request.getRequestedSessionId()));

//		去掉 Struts2 的依赖项, 改用 Spring, 需要配置
//		<listener>
//		  <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
//		</listener>
//		if (request == null)
//			request = ServletActionContext.getRequest();

		if (request == null) {
			request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
		}

		return request;
	}

}
